package com.ztesoft.book.api.config.shiro.handler;

import com.ztesoft.book.api.controller.base.BaseController;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Description Shiro自定义注解
 * @Author YangFan
 * @Date 2021-07-07 23:44
 */
public class MyAuthorizationAttributeSourceAdvisor extends AuthorizationAttributeSourceAdvisor {

    private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES = new Class[]{RequiresPermissions.class, RequiresRoles.class, RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class};

    /**
     * web注解
     */
    private static final Class<? extends Annotation>[] WEB_ANNOTATION_CLASSES = new Class[]{RequestMapping.class};

    private SecurityManager securityManager = null;

    /**
     * 这里使用自定义切面
     */
    public MyAuthorizationAttributeSourceAdvisor() {
        setAdvice(new MyAop());
    }


    /**
     * 方法功能描述:
     * < 匹配带有注解的类和方法 >
     *
     * @param method      【参数 1 注释说明】
     * @param targetClass 【参数 2 注释说明】
     * @return boolean                        【返回值 注释说明】
     * @author YangFan
     * @date 2021-07-07 23:45
     */
    @Override
    public boolean matches(Method method, Class targetClass) {
        boolean flag = false;

        // 2021-10-13调整：去除BaseController的继承检测，目前Class的注解是开关，如果Class没有注解则整个类中的权限校验都无效
        if (isAuthzAnnotationPresent(targetClass) && isAuthzAnnotationPresent(method) && isWebAnnotationPresent(method)) {
            flag = true;
        }
        return flag;
    }


    /**
     * 方法功能描述:
     * < 查看BaseController的子类是否有权限注解 >
     *
     * @param clazz 【参数 1 注释说明】
     * @return boolean                        【返回值 注释说明】
     * @author YangFan
     * @date 2021-07-07 23:46
     */
    private boolean isAuthzAnnotationPresent(Class<BaseController> clazz) {

        for (Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
            Annotation a = AnnotationUtils.findAnnotation(clazz, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }


    /**
     * 方法功能描述:
     * < 查看方法上是否有权限注解 >
     *
     * @param method 【参数 1 注释说明】
     * @return boolean                        【返回值 注释说明】
     * @author YangFan
     * @date 2021-07-07 23:46
     */
    private boolean isAuthzAnnotationPresent(Method method) {
        for (Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }


    /**
     * 方法功能描述:
     * < 查看方法是否有web注解，是否是一个rest接口 >
     *
     * @param method 【参数 1 注释说明】
     * @return boolean                        【返回值 注释说明】
     * @author YangFan
     * @date 2021-07-07 23:46
     */
    private boolean isWebAnnotationPresent(Method method) {
        for (Class<? extends Annotation> annClass : WEB_ANNOTATION_CLASSES) {
            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }


    @Override
    public SecurityManager getSecurityManager() {
        return securityManager;
    }

    @Override
    public void setSecurityManager(SecurityManager sm) {
        this.securityManager = sm;
    }
}
